package main

import (
	"context"
	"encoding/json"
	"fmt"
	"kline/goex"
	"kline/goex/builder"
	"kline/goex/okex"
	"kline/logger"
	"kline/mongo"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"
)

type Chart struct {
	Time                 int64  `json:"time"`                 //5分钟 10分钟
	Hold                 string `json:"hold"`                 //持仓量
	Symbol               string `json:"symbol"`               //币种
	CiJiPrice            string `json:"ci_ji_price"`          //次季度
	DangJiPrice          string `json:"dangji_price"`         //当季
	XhPrice              string `json:"xh_price"`             //现货
	DangZhouPrice        string `json:"dang_zhou_price"`      //当周
	CiZhouPrice          string `json:"ci_zhou_price"`        //次周
	YongXuPrice          string `json:"yong_xu_price"`        //永续
	XhTradeSellAmount    string `json:"xh_trade_sell_amount"` //卖单成交量
	XhTradeBuyAmount     string `json:"xh_trade_buy_amount"`  //买单成交量
	DangZTradeSellAmount string `json:"dz_trade_sell_amount"` //卖单成交量
	DangZTradeBuyAmount  string `json:"dz_trade_buy_amount"`  //买单成交量
	CiZTradeSellAmount   string `json:"cz_trade_sell_amount"` //卖单成交量
	CiZTradeBuyAmount    string `json:"cz_trade_buy_amount"`  //买单成交量
	JdTradeSellAmount    string `json:"jd_trade_sell_amount"` //卖单成交量
	JdTradeBuyAmount     string `json:"jd_trade_buy_amount"`  //买单成交量
	CjTradeSellAmount    string `json:"cj_trade_sell_amount"` //卖单成交量
	CjTradeBuyAmount     string `json:"cj_trade_buy_amount"`  //买单成交量
	YxTradeSellAmount    string `json:"yx_trade_sell_amount"` //卖单成交量
	YxTradeBuyAmount     string `json:"Yx_trade_buy_amount"`  //买单成交量
}

func NewChart(symbol string, time int64) Chart {
	return Chart{
		time,
		"0",
		symbol,
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
		"0",
	}
}

const ACTION_UPDATE_HOLDS = 1 //持仓
const ACTION_UPDATE_DEPTH = 2 //深度
const ACTION_UPDATE_TRADE = 3 //交易

type UpdateChartData struct {
	symbol string
	data   interface{}
	action int
}

type OkRobot struct {
	futureApi        goex.FutureRestAPI
	futureWsApi      goex.FuturesWsApi
	spotWsApi        goex.SpotWsApi
	api              goex.API
	futures          map[string]okex.FutureContractInfo
	spots            map[goex.CurrencyPair]okex.FutureContractInfo
	holds            []okex.HoldResponse
	charts           map[string]map[int64]Chart
	chartsUpdateChan chan UpdateChartData
	srv              http.Server
	context          context.Context
	cancel           context.CancelFunc
	lastSaveTime     map[string]int64
	symbols          map[string]string
}

const TABLE_NAME = "okex2020_5min"

func (this *OkRobot) SaveToDB(symbol string) {
	list, ok := this.charts[symbol]
	if !ok {
		return
	}

	keys := make([]int, 0)
	for k, _ := range list {
		keys = append(keys, int(k))
	}
	sort.Ints(keys)
	// logger.Log.Info(symbol, len(keys))
	if len(list) > mongo.MAX_COUNT {
		//保存第一条到数据库
		for i := 0; i < len(list)-mongo.MAX_COUNT; i++ {
			logger.Log.Info("删除数据")
			//如果大于mongo.MAX_COUNT 就少一个数据
			delete(this.charts[symbol], int64(keys[i]))
		}
	}
	for i := 0; i < len(keys) && len(keys) > 1; i++ {
		v := list[int64(keys[i])]
		last, ok := this.lastSaveTime[symbol]
		if !ok {
			last = 0
		}
		if v.Time <= last {
			continue
		}
		err := mongo.Get(TABLE_NAME, symbol, v.Time)
		if err != nil {
			//已存在
			logger.Log.Info(err)
			continue
		}
		logger.Log.Info("存储数据")
		err = mongo.Insert(TABLE_NAME, v)
		if err != nil {
			//添加数据
			logger.Log.Info(err)
			continue
		}
		this.lastSaveTime[symbol] = v.Time
	}
}

//检查持仓变化信息
func (this *OkRobot) UpdatePosition(ctx context.Context) {
	t := time.NewTicker(30 * time.Second)
	defer t.Stop()
	for {
		select {
		case <-ctx.Done():
			logger.Log.Info("退出更新仓位变化")
			return
		case <-t.C:
			for _, v := range this.futures {
				if v.Alias == goex.SPOT_CONTRACT {
					//现货没有持仓
					continue
				}
				cmd := UpdateChartData{}
				cmd.symbol = v.UnderlyingIndex
				if v.Alias != goex.SWAP_CONTRACT {
					holds, err := this.futureApi.(*okex.OKExFuture).GetFutureHolds(v.InstrumentID)
					if err != nil {
						time.Sleep(1 * time.Second)
						continue
					}
					if len(this.holds) >= 1000 {
						this.InsertHolds()
					}
					this.holds = append(this.holds, *holds)
					cmd.action = ACTION_UPDATE_HOLDS
					cmd.data = holds
					this.chartsUpdateChan <- cmd
				} else { //永续持仓
					holds, err := this.futureApi.(*okex.OKExFuture).GetSwapHolds(v.InstrumentID)
					if err != nil {
						time.Sleep(1 * time.Second)
						continue
					}
					if len(this.holds) >= 1000 {
						this.InsertHolds()
					}
					this.holds = append(this.holds, *holds)
					cmd.data = holds
					this.chartsUpdateChan <- cmd
				}
			}
		}
	}
}

func (this *OkRobot) SubscribeSymbols() {
	futures, err := this.futureApi.(*okex.OKExFuture).GetAllFutureContractInfo()
	if err != nil {
		logger.Log.Info(err)
		time.Sleep(10 * time.Second)
		return
	}
	for _, v := range futures {
		if v.QuoteCurrency == "USDT" {
			//USD 是币本位 USDT 是钱本位
			continue
		}
		currencyA := goex.NewCurrency(v.UnderlyingIndex, v.UnderlyingIndex)
		currencyB := goex.NewCurrency(v.QuoteCurrency, v.QuoteCurrency)
		currencyPair := goex.CurrencyPair{currencyA, currencyB}
		_, ok := this.futures[v.InstrumentID]
		if !ok {
			//============================== 期货订阅
			//订阅深度
			err := this.api.(*okex.OKEx).OKExV3FutureWs.SubscribeDepth(currencyPair, v.Alias)
			if err != nil {
				logger.Log.Info(err)
				time.Sleep(10 * time.Second)
				continue
			}
			//订阅交易
			err = this.api.(*okex.OKEx).OKExV3FutureWs.SubscribeTrade(currencyPair, v.Alias)
			if err != nil {
				logger.Log.Info(err)
				time.Sleep(10 * time.Second)
				continue
			}

			//不存在就订阅
			this.futures[v.InstrumentID] = v
		}
		_, ok = this.symbols[currencyPair.CurrencyA.Symbol]
		if !ok {
			var data []Chart
			//symbol
			err = mongo.GetList(TABLE_NAME, currencyPair.CurrencyA.Symbol, &data)
			if err != nil {
				logger.Log.Info(err)
			} else {
				logger.Log.Info("查询数据", currencyPair.CurrencyA.Symbol)
				for _, d := range data {
					if _, ok := this.charts[currencyPair.CurrencyA.Symbol]; !ok {
						this.charts[currencyPair.CurrencyA.Symbol] = map[int64]Chart{}
					}
					this.charts[currencyPair.CurrencyA.Symbol][d.Time] = d
				}
			}
			this.symbols[currencyPair.CurrencyA.Symbol] = currencyPair.CurrencyA.Symbol
		}
		spotPair := currencyPair
		if spotPair.CurrencyB.Symbol == "USD" {
			spotPair.CurrencyB.Symbol += "T"
		}
		_, ok = this.spots[spotPair]
		if !ok {
			//=========================== 永续期货订阅
			err := this.api.(*okex.OKEx).OKExV3FutureWs.SubscribeDepth(currencyPair, goex.SWAP_CONTRACT)
			if err != nil {
				logger.Log.Info(err)
				time.Sleep(10 * time.Second)
				continue
			}
			//订阅交易
			err = this.api.(*okex.OKEx).OKExV3FutureWs.SubscribeTrade(currencyPair, goex.SWAP_CONTRACT)
			if err != nil {
				logger.Log.Info(err)
				time.Sleep(10 * time.Second)
				continue
			}
			contractId := fmt.Sprintf("%s-SWAP", currencyPair.ToSymbol("-"))
			v.Alias = goex.SWAP_CONTRACT
			this.futures[contractId] = v

			contractId = spotPair.ToSymbol("-") + "-" + goex.SPOT_CONTRACT
			v.Alias = goex.SPOT_CONTRACT
			//=========================== 现货订阅
			err = this.api.(*okex.OKEx).OKExV3SpotWs.SubscribeTrade(spotPair)
			if err != nil {
				logger.Log.Info(err)
				time.Sleep(10 * time.Second)
				continue
			}
			err = this.api.(*okex.OKEx).OKExV3SpotWs.SubscribeDepth(spotPair)
			if err != nil {
				logger.Log.Info(err)
				time.Sleep(10 * time.Second)
				continue
			}
			this.futures[contractId] = v
			this.spots[spotPair] = v
		}
	}
}

//更新订阅 每小时检查一次变化
func (this *OkRobot) UpdateInstruments(ctx context.Context) {
	t := time.NewTicker(1 * time.Hour)
	defer t.Stop()
	this.SubscribeSymbols()
	for {
		select {
		case <-ctx.Done():
			logger.Log.Info("退出更新订阅")
			return
		case <-t.C:
			this.SubscribeSymbols()
		}

	}
}

func main() {
	logger.Log.Info("程序启动")
	wg := sync.WaitGroup{}
	proxy := os.Getenv("http_proxy")
	var conf *builder.HttpClientConfig
	if proxy != "" {
		logger.Log.Info("代理访问")
		//代理访问
		proxyUrl := "http://127.0.0.1:1080"
		purl, _ := url.Parse(proxyUrl)
		pxy := http.ProxyURL(purl)
		p, _ := pxy(nil)
		conf = &builder.HttpClientConfig{
			Proxy:        p,
			HttpTimeout:  5 * time.Second,
			MaxIdleConns: 10}
	} else {
		logger.Log.Info("无代理访问")
		conf = &builder.HttpClientConfig{
			Proxy:        nil,
			HttpTimeout:  5 * time.Second,
			MaxIdleConns: 10}
	}
	logger.Log.Info("创建api")
	apiBuilder := builder.NewAPIBuilder2(conf).HttpTimeout(5 * time.Second)
	robot := &OkRobot{
		futures:          map[string]okex.FutureContractInfo{},
		spots:            map[goex.CurrencyPair]okex.FutureContractInfo{},
		charts:           map[string]map[int64]Chart{},
		chartsUpdateChan: make(chan UpdateChartData, 1),
		srv:              http.Server{},
		symbols:          map[string]string{},
		lastSaveTime:     map[string]int64{},
	}
	ctx, cancel := context.WithCancel(context.Background())
	robot.futureApi = apiBuilder.APIKey("b0b114f3-96aa-4f03-9f83-1207a8e771a3").
		APISecretkey("EDEF91B4A52E9B6C821786B022112669").ApiPassphrase("TG159357").
		BuildFuture(goex.OKEX_FUTURE)
	robot.api = apiBuilder.APIKey("b0b114f3-96aa-4f03-9f83-1207a8e771a3").
		APISecretkey("EDEF91B4A52E9B6C821786B022112669").ApiPassphrase("TG159357").
		Build(goex.OKEX_V3)
	//期货合约处理 包括永续的处理
	logger.Log.Info("订阅设置回调函数")
	robot.api.(*okex.OKEx).OKExV3FutureWs.SetCallbacks(func(ticker *goex.FutureTicker) {

	}, func(depth *goex.Depth) {
		//深度信息
		cmd := UpdateChartData{}
		cmd.action = ACTION_UPDATE_DEPTH
		cmd.symbol = depth.Pair.CurrencyA.Symbol
		cmd.data = depth
		robot.chartsUpdateChan <- cmd
	}, func(trade *goex.Trade, s string) {
		//交易信息
		cmd := UpdateChartData{}
		cmd.action = ACTION_UPDATE_TRADE
		cmd.symbol = trade.Pair.CurrencyA.Symbol
		cmd.data = trade
		robot.chartsUpdateChan <- cmd
	}, func(kline *goex.FutureKline, i int) {

	})
	logger.Log.Info("现货订阅设置回调函数")
	//现货订阅处理
	robot.api.(*okex.OKEx).OKExV3SpotWs.SetCallbacks(func(ticker *goex.Ticker) {

	}, func(depth *goex.Depth) {
		//深度信息
		cmd := UpdateChartData{}
		cmd.action = ACTION_UPDATE_DEPTH
		cmd.symbol = depth.Pair.CurrencyA.Symbol
		cmd.data = depth
		robot.chartsUpdateChan <- cmd
	}, func(trade *goex.Trade) {
		trade.InstrumentID += "-" + goex.SPOT_CONTRACT
		//交易信息
		cmd := UpdateChartData{}
		cmd.action = ACTION_UPDATE_TRADE
		cmd.symbol = trade.Pair.CurrencyA.Symbol
		cmd.data = trade
		robot.chartsUpdateChan <- cmd
	}, func(kline *goex.Kline, period goex.KlinePeriod) {

	})
	sigc := make(chan os.Signal, 1)
	signal.Notify(sigc, os.Interrupt, os.Kill)
	wg.Add(1)
	go func() {
		defer wg.Done()
		logger.Log.Info("设置map")
		robot.SetMap(ctx)
	}()
	wg.Add(1)
	go func() {
		defer wg.Done()
		logger.Log.Info("更新symbol")
		robot.UpdateInstruments(ctx)
	}()
	wg.Add(1)
	go func() {
		defer wg.Done()
		logger.Log.Info("更新持仓")
		robot.UpdatePosition(ctx)
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		robot.ServerHttp()
	}()

	wg.Add(1)
	go func() {
		defer wg.Done()
		select {
		case <-sigc:
			logger.Log.Info("Ctrl+C Exit")
			cancel()
			if err := robot.srv.Shutdown(ctx); err != nil {
				logger.Log.Fatalf("Server Shutdown Failed:%+v", err)
			}
		}
	}()
	wg.Wait()
}

type JsonResult struct {
	Code int         `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

func JsonResponse(w http.ResponseWriter, code int, msg string, data interface{}) {
	w.Header().Set("Content-Type", "application/json")
	res := JsonResult{
		Code: code,
		Msg:  msg,
		Data: data,
	}
	_ = json.NewEncoder(w).Encode(res)
}
func (this *OkRobot) myHandler(w http.ResponseWriter, r *http.Request) {
	params := r.URL.Query()
	symbol := params.Get("symbol")
	if symbol == "" {
		symbol = "BTC"
	}
	symbol = strings.ToUpper(symbol)
	date := params.Get("date")
	ts1 := int64(0)
	if date == "" {
		ts, _ := strconv.Atoi(date)
		ts1 = CalcCurrentFiveMin(time.Unix(int64(ts), 0))
	}
	result, ok := this.charts[symbol]
	if !ok {
		JsonResponse(w, 400, "数据未同步", map[string]interface{}{})
		return
	}
	if ts1 <= 0 {
		JsonResponse(w, 200, "ok", result)
		return
	}
	c, ok := result[ts1]
	if !ok {
		JsonResponse(w, 400, "数据未同步", map[string]interface{}{})
		return
	}
	JsonResponse(w, 200, "ok", c)
	return
}
func (this *OkRobot) chartsStrategy(w http.ResponseWriter, r *http.Request) {
	params := r.URL.Query()
	symbol := params.Get("symbol")
	if symbol == "" {
		symbol = "BTC"
	}
	symbol = strings.ToUpper(symbol)
	from := params.Get("from")
	if from == "" {
		from = goex.QUARTER_CONTRACT
	}
	to := params.Get("to")
	if to == "" {
		to = goex.SPOT_CONTRACT
	}
	list, ok := this.charts[symbol]
	if !ok {
		JsonResponse(w, 400, "数据未同步", map[string]interface{}{})
		return
	}
	dates := make([]string, 0)
	toData := make([]string, 0)
	fromData := make([]string, 0)
	jcData := make([]string, 0)
	holds := make([]string, 0)
	tradeBuyAmount := make([]string, 0)
	tradeSellAmount := make([]string, 0)
	keys := make([]int, 0)
	for k, _ := range list {
		keys = append(keys, int(k))
	}
	sort.Ints(keys)
	for i := 0; i < len(keys)-1; i++ {
		v := list[int64(keys[i])]
		dates = append(dates, FormatTime(time.Unix(v.Time, 0)))
		holds = append(holds, v.Hold)
		td := ""
		fd := ""
		switch to {
		case goex.SPOT_CONTRACT:
			td = v.XhPrice
			tradeBuyAmount = append(tradeBuyAmount, v.XhTradeBuyAmount)
			tradeSellAmount = append(tradeSellAmount, v.XhTradeSellAmount)
		case goex.THIS_WEEK_CONTRACT:
			td = v.DangZhouPrice
			tradeBuyAmount = append(tradeBuyAmount, v.DangZTradeBuyAmount)
			tradeSellAmount = append(tradeSellAmount, v.DangZTradeSellAmount)
		case goex.NEXT_WEEK_CONTRACT:
			tradeBuyAmount = append(tradeBuyAmount, v.CiZTradeBuyAmount)
			tradeSellAmount = append(tradeSellAmount, v.CiZTradeSellAmount)
			td = v.CiZhouPrice
		case goex.QUARTER_CONTRACT:
			tradeBuyAmount = append(tradeBuyAmount, v.JdTradeBuyAmount)
			tradeSellAmount = append(tradeSellAmount, v.JdTradeSellAmount)
			td = v.DangJiPrice
		case goex.BI_QUARTER_CONTRACT:
			tradeBuyAmount = append(tradeBuyAmount, v.CiZTradeBuyAmount)
			tradeSellAmount = append(tradeSellAmount, v.CiZTradeSellAmount)
			td = v.CiJiPrice
		case goex.SWAP_CONTRACT:
			tradeBuyAmount = append(tradeBuyAmount, v.YxTradeBuyAmount)
			tradeSellAmount = append(tradeSellAmount, v.YxTradeSellAmount)
			td = v.YongXuPrice
		}
		toData = append(toData, td)
		switch from {
		case goex.SPOT_CONTRACT:
			fd = v.XhPrice
		case goex.THIS_WEEK_CONTRACT:
			fd = v.DangZhouPrice
		case goex.NEXT_WEEK_CONTRACT:
			fd = v.CiZhouPrice
		case goex.QUARTER_CONTRACT:
			fd = v.DangJiPrice
		case goex.BI_QUARTER_CONTRACT:
			fd = v.CiJiPrice
		case goex.SWAP_CONTRACT:
			fd = v.YongXuPrice
		}
		fromData = append(fromData, fd)
		jcData = append(jcData, StringSub(fd, td))
	}
	JsonResponse(w, 200, "ok", map[string]interface{}{
		"timeData": dates, "xhData": toData, "qhData": fromData, "position": holds, "jcData": jcData,
		"tradeBuy":  tradeBuyAmount,
		"tradeSell": tradeSellAmount,
	})
	return
}
func (this *OkRobot) ServerHttp() {
	http.HandleFunc("/test", this.myHandler)
	http.HandleFunc("/charts-strategy", this.chartsStrategy)
	this.srv.Addr = ":8089"
	logger.Log.Infof("http server %s", this.srv.Addr)
	if err := this.srv.ListenAndServe(); err != http.ErrServerClosed {
		// Error starting or closing listener:
		logger.Log.Infof("HTTP server ListenAndServe: %v", err)
	}
}
func (this *OkRobot) InsertHolds() {
	data := make([]interface{}, 0)
	for _, m := range this.holds {
		b, _ := json.Marshal(m)
		var r map[string]interface{}
		_ = json.Unmarshal(b, &r)
		r["time"] = m.Timestamp.Unix()
		r["time_format"] = FormatTime(m.Timestamp)
		contractInfo, _ := this.futures[m.InstrumentId]
		r["contractType"] = contractInfo.Alias
		r["symbol"] = contractInfo.UnderlyingIndex
		data = append(data, r)
	}
	err := mongo.InsertMany("position", data)
	if err != nil {
		logger.Log.Info(err)
		return
	}
	this.holds = make([]okex.HoldResponse, 0)
}

func (this *OkRobot) SetMap(ctx context.Context) {
	t := time.NewTicker(time.Second * 60)
	for {
		select {
		case <-ctx.Done():
			logger.Log.Info("结束 入库服务")
			return
		case cmd := <-this.chartsUpdateChan:
			switch cmd.action {
			case ACTION_UPDATE_HOLDS:
				this.InsertHoldsMap(cmd.data.(*okex.HoldResponse), cmd.symbol)
			case ACTION_UPDATE_DEPTH:
				this.InsertDepthMap(cmd.data.(*goex.Depth), cmd.symbol)
			case ACTION_UPDATE_TRADE:
				this.InsertTradeMap(cmd.data.(*goex.Trade), cmd.symbol)
			default:
				continue
			}
			this.SaveToDB(cmd.symbol)
		case <-t.C:
			continue
		}

	}
}

func (this *OkRobot) InsertHoldsMap(holds *okex.HoldResponse, symbol string) {
	//填充 图表中的数据
	_, ok := this.charts[symbol]
	if !ok {
		this.charts[symbol] = map[int64]Chart{}
	}
	indexMin := CalcCurrentFiveMin(holds.Timestamp)
	c, ok := this.charts[symbol][indexMin]
	if !ok {
		c = NewChart(symbol, indexMin)
	}
	amount, _ := strconv.ParseFloat(holds.Amount, 64)
	c.Hold = StringAverage(c.Hold, amount)
	this.charts[symbol][indexMin] = c
}

func (this *OkRobot) InsertDepthMap(depth *goex.Depth, symbol string) {
	//填充 图表中的数据
	_, ok := this.charts[symbol]
	if !ok {
		this.charts[symbol] = map[int64]Chart{}
	}
	indexMin := CalcCurrentFiveMin(depth.UTime)
	c, ok := this.charts[symbol][indexMin]
	if !ok {
		c = NewChart(symbol, indexMin)
	}
	switch depth.ContractType {
	case goex.SPOT_CONTRACT:
		c.XhPrice = StringAverage(c.XhPrice, depth.BidList[0].Price)
	case goex.THIS_WEEK_CONTRACT:
		c.DangZhouPrice = StringAverage(c.DangZhouPrice, depth.AskList[0].Price)
	case goex.NEXT_WEEK_CONTRACT:
		c.CiZhouPrice = StringAverage(c.CiZhouPrice, depth.AskList[0].Price)
	case goex.QUARTER_CONTRACT:
		c.DangJiPrice = StringAverage(c.DangJiPrice, depth.AskList[0].Price)
	case goex.BI_QUARTER_CONTRACT:
		c.CiJiPrice = StringAverage(c.CiZhouPrice, depth.AskList[0].Price)
	case goex.SWAP_CONTRACT:
		c.YongXuPrice = StringAverage(c.YongXuPrice, depth.AskList[0].Price)
	default:
		return
	}
	this.charts[symbol][indexMin] = c
}

func (this *OkRobot) InsertTradeMap(trade *goex.Trade, symbol string) {
	//填充 图表中的数据
	_, ok := this.charts[symbol]
	if !ok {
		this.charts[symbol] = map[int64]Chart{}
	}
	indexMin := CalcCurrentFiveMin(time.Unix(trade.Date, 0))
	c, ok := this.charts[symbol][indexMin]
	if !ok {
		c = NewChart(symbol, indexMin)
	}
	contractInfo, ok := this.futures[trade.InstrumentID]
	if !ok {
		return
	}
	switch contractInfo.Alias {
	case goex.SPOT_CONTRACT: //现货
		if trade.Type == goex.BUY {
			c.XhTradeBuyAmount = StringAdd(c.XhTradeBuyAmount, fmt.Sprintf("%f", trade.Price*trade.Amount))
		} else {
			c.XhTradeSellAmount = StringAdd(c.XhTradeSellAmount, fmt.Sprintf("%f", trade.Price*trade.Amount))
		}

	case goex.THIS_WEEK_CONTRACT:
		if trade.Type == goex.BUY {
			c.DangZTradeBuyAmount = StringAdd(c.DangZTradeBuyAmount, fmt.Sprintf("%f", trade.Price*trade.Amount))
		} else {
			c.DangZTradeSellAmount = StringAdd(c.DangZTradeSellAmount, fmt.Sprintf("%f", trade.Price*trade.Amount))
		}
	case goex.NEXT_WEEK_CONTRACT:
		if trade.Type == goex.BUY {
			c.CiZTradeBuyAmount = StringAdd(c.CiZTradeBuyAmount, fmt.Sprintf("%f", trade.Price*trade.Amount))
		} else {
			c.CiZTradeSellAmount = StringAdd(c.CiZTradeSellAmount, fmt.Sprintf("%f", trade.Price*trade.Amount))
		}
	case goex.QUARTER_CONTRACT:
		if trade.Type == goex.BUY {
			c.JdTradeBuyAmount = StringAdd(c.JdTradeBuyAmount, fmt.Sprintf("%f", trade.Price*trade.Amount))
		} else {
			c.JdTradeSellAmount = StringAdd(c.JdTradeSellAmount, fmt.Sprintf("%f", trade.Price*trade.Amount))
		}
	case goex.BI_QUARTER_CONTRACT:
		if trade.Type == goex.BUY {
			c.CjTradeBuyAmount = StringAdd(c.CjTradeBuyAmount, fmt.Sprintf("%f", trade.Price*trade.Amount))
		} else {
			c.CjTradeSellAmount = StringAdd(c.CjTradeSellAmount, fmt.Sprintf("%f", trade.Price*trade.Amount))
		}
	case goex.SWAP_CONTRACT:
		if trade.Type == goex.BUY {
			c.YxTradeBuyAmount = StringAdd(c.YxTradeBuyAmount, fmt.Sprintf("%f", trade.Price*trade.Amount))
		} else {
			c.YxTradeSellAmount = StringAdd(c.YxTradeSellAmount, fmt.Sprintf("%f", trade.Price*trade.Amount))
		}
	default:
		return
	}
	this.charts[symbol][indexMin] = c
}

func FormatTime(t time.Time) string {
	return t.Format("2006-01-02 15:04:05")
}

func CalcCurrentFiveMin(t time.Time) int64 {
	ts := t.Unix()
	sec := int64(5 * 60) //5 min
	left := ts % sec
	ts -= left
	return ts
}

func StringAdd(s1, s2 string) string {
	if s1 == "" {
		s1 = "0"
	}
	if s2 == "" {
		s2 = "0"
	}
	f1, _ := strconv.ParseFloat(s1, 64)
	f2, _ := strconv.ParseFloat(s2, 64)
	return fmt.Sprintf("%f", f1+f2)
}

func StringSub(s1, s2 string) string {
	if s1 == "" {
		s1 = "0"
	}
	if s2 == "" {
		s2 = "0"
	}
	f1, _ := strconv.ParseFloat(s1, 64)
	f2, _ := strconv.ParseFloat(s2, 64)
	return fmt.Sprintf("%f", f1-f2)
}

func StringAverage(s1 string, f2 float64) string {
	if s1 == "" {
		s1 = "0"
	}
	f1, _ := strconv.ParseFloat(s1, 64)
	if f1 <= 0 {
		return fmt.Sprintf("%f", f2)
	}
	return fmt.Sprintf("%f", (f1+f2)/2.00)
}
